package by.jabbby.service;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smackx.ChatState;
import org.jivesoftware.smackx.ChatStateManager;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import by.jabbby.Logger;
import by.jabbby.dataprovider.Account;
import by.jabbby.dataprovider.AccountProvider;
import by.jabbby.dataprovider.ApplicationPreference;
import by.jabbby.dataprovider.ChatEntry;
import by.jabbby.dataprovider.ChatProvider;
import by.jabbby.service.listener.JabberConnectionListener;
import by.jabbby.service.listener.JabberPacketListener;
import by.jabbby.ui.data.RosterEntryObj;

public class JabberService extends Service implements ConnectionCreationListener, org.jivesoftware.smack.MessageListener {
	public static final String ACTION_CHANGE_STATUS = "jabbby.actions.changestatus";
	public static final String ACTION_NEW_MESSAGE = "jabby.actions.newmessage";
	public static final String ACTION_NEW_MESSAGE_BODY = "jabby.actions.newmessage.content";
	public static final String ACTION_NEW_MESSAGE_CHAT = "jabby.actions.newmessage.chat";

	public static final String ACTION_CONNECTION_RECONNECT = "jabby.actions.connection.reconect";
	public static final String ACTION_CONNECTION_CLOSED_WITH_ERROR = "jabby.actions.connection.closed_error";
	public static final String ACTION_CONNECTION_CLOSED = "jabby.actions.connection.closed";
	public static final String ACTION_CONNECTION_RECONNECT_INSECOND = "jabby.actions.connection.reconect.insecond";
	public static final String ACTION_CONNECTION_RECONNECT_SUCCESSFULL = "jabby.actions.connection.reconect.successfull";
	public static final String ACTION_CONNECTION_RECONNECT_FAILED = "jabby.actions.connection.reconect.failed";
	public static final String ACTION_CONNECTION_LOGIN = "jabby.actions.connection.login";
	public static final String ACTION_CONNECTION_LOGIN_FAILED = "jabby.actions.connection.login.failed";
	public static final String ACTION_NOTIFICATION_NEW_MESSAGE = "jabby.actions.notification.newmessage";
	public static final String ACTION_NOTIFICATION_NEW_MESSAGE_FROM = "jabby.actions.notification.newmessage.from";
	
	public static final String NEW_MESSAGE_process = "process";
	// public static final String ACTION_NEW_MESSAGE_CHAT =
	// "jabby.actions.connection.reconect";
	// public static final String ACTION_NEW_MESSAGE_CHAT =
	// "jabby.actions.connection.reconect";

	private final IJabberService.Stub binder = new IJabberService.Stub() {

		public void connect(String jid) throws RemoteException {
			int conne = 0;
			conne++;

		}

		public void disconnect(String jid) throws RemoteException {
			try {
				if (connection.isConnected()) {
					connection.disconnect();
					this.changeStatus(Status.OfLine.name());
				}
			} catch (Exception e) {
				Logger.e("Error on JabberService disconnect", e);
			}

		}

		public void exit() throws RemoteException {
			try {
				JabberService.this.connection.disconnect();
				JabberService.this.stopSelf();
			} catch (Exception e) {
				Logger.e(e);
			}
		}

		public boolean isConnected() throws RemoteException {
			if ((JabberService.this.connection == null) || (!JabberService.this.connection.isConnected())) {
				return false;
			}
			return true;
		}

		public void activeChat(String jid) {
			try {
				if (connection.isAuthenticated()) {
					ChatManager chm = connection.getChatManager();
					Chat chat = chm.getThreadChat(jid);
					if (chat != null) {
						Logger.i("Chat currently active: " + jid);
					} else {
						 chat = chm.createChat(jid, jid, JabberService.this);
						Logger.i("Create new chat: " + jid);
						ChatStateManager.getInstance(JabberService.this.connection).setCurrentState(ChatState.active, chat);
					}
				} else {
					Logger.i("Chat can not be activate. User is not  authenticated  ");
				}

			} catch (Exception e) {
				Logger.e("activeChat", e);
			}
		}

		public void closeChat(String jid) {
			try {
				if (connection.isAuthenticated()) {
					ChatManager chm = connection.getChatManager();
					Chat chat = chm.getThreadChat(jid);
					chm.removeChat(chat);
				} else {
					Logger.e("Chat can not be activate. User is not  authenticated  ");
				}

			} catch (Exception e) {
				Logger.e("activeChat", e);
			}

		}

		public void sendMessage(String outJid, String msg) throws RemoteException {
			// connection.getRoster().getEntry(outJid);
			try {

				if (connection.isAuthenticated()) {
					ChatManager chm = connection.getChatManager();
					Chat chat = chm.getThreadChat(outJid);
					if (chat == null) {
						chat = chm.createChat(outJid, outJid, JabberService.this);
					}
					chat.sendMessage(msg);
					ChatProvider cp = new ChatProvider(account.getConnectionString(), JabberService.this.getApplicationContext());
					cp.addEntry(new ChatEntry(msg, account.getConnectionString(), outJid));
				} else {
					Logger.e("Message can not be send. User is not  authenticated  ");
				}

			} catch (Exception e) {
				Logger.e("JabberServcie.sendMessage", e);
			}
		}

		public void changeStatus(String status) throws RemoteException {
			try {
				if (status.equalsIgnoreCase(Status.OnLine.name())) {
					XMPPConnection conn = getLoggInConnection();
					if (conn.isConnected() && conn.isAuthenticated()) {
						try {
							currentStatus = Status.OnLine;
							Presence presence = new Presence(Presence.Type.available);
							presence.setStatus("Online, Programmatically!");
							presence.setPriority(24);
							presence.setMode(currentStatus.getPresenceMode());
							// user.getConnection().sendPacket(presence);
							conn.sendPacket(presence);

							JabberService.this.currentStatus = Status.valueOf(status);
							Intent intt = new Intent(JabberService.ACTION_CHANGE_STATUS);
							// intt.setAction(Status.OnLine.name());
							sendBroadcast(intt);

						} catch (Exception e) {
							Logger.e(e);
						}
					}
				} else {
					if (status.equalsIgnoreCase(Status.OfLine.name())) {
						if (JabberService.this.connection.isConnected()) {
							JabberService.this.connection.disconnect();
							JabberService.this.currentStatus = Status.valueOf(status);
							
							Intent intt = new Intent(JabberService.ACTION_CHANGE_STATUS);
							sendBroadcast(intt);
						}
						
					}
					
				}

			} catch (Exception e) {
				Logger.e(e.getMessage(), e);

			} finally {

			}
		}

		public String getCurrentStatus() throws RemoteException {

			return JabberService.this.currentStatus.name();
		}

		public RosterEntryObj[] getRosters() throws RemoteException {
			RosterEntryObj[] result = null;
			try {
				if (this.isLoggin()) {
					// if(getCurrentStatus().equals(Status.OfLine.name())){
					// this.changeStatus(Status.OnLine.name());
					// }
					Roster roster = JabberService.this.getLoggInConnection().getRoster();
					Collection<RosterEntry> re = roster.getEntries();					
					result = new RosterEntryObj[re.size()];
					int i = 0;
					for (RosterEntry r : re) {
						RosterEntryObj tmp = new RosterEntryObj(r);
						result[i] = tmp;
						i++;						
					}
					Arrays.sort(result, new RosterEntryObj.ComparatorByJID());
				}
			} catch (Exception e) {
				Logger.e(e);
			}
			return result;
		}

		public boolean isLoggin() throws RemoteException {
			if (isConnected() && (JabberService.this.connection.isAuthenticated())) {

				return true;
			}
			return false;
		}

	};

	/*
	 * public class LocalBinder extends Binder { public JabberService
	 * getService() { return JabberService.this; } }
	 */
	private ConnectionConfiguration connectionConfiguration;
	private Account account;
	private XMPPConnection connection;
	private Status currentStatus;

	public Account getAccount() {
		return account;
	}

	public XMPPConnection getConnection() {
		try {
			if (connection == null) {
				AccountProvider ap = new AccountProvider(this.getApplicationContext());
				account = ap.getCurrentAccount();
				connectionConfiguration = new ConnectionConfiguration(account.getJabberServer().getHost(), account.getJabberServer().getPort());

				connection = new XMPPConnection(connectionConfiguration);

				connection.connect();
				// connection.login(account.getLogin(), account.getPassword());
			} else {
				if (!connection.isConnected()) {
					connection.connect();
				}
			}
		} catch (Exception e) {
			Logger.e("Error when get connection", e);
			if (connection != null) {
				if (connection.isConnected()) {
					connection.disconnect();
				}
				connection = null;
			}
		}
		return connection;
	}

	private XMPPConnection getLoggInConnection() {
		try {

			XMPPConnection conn = getConnection();

			if (!conn.isAuthenticated()) {
				AccountProvider ap = new AccountProvider(this.getApplicationContext());
				account = ap.getCurrentAccount();
				conn.login(account.getLogin(), account.getPassword());
				if (conn.isAuthenticated()) {
					Logger.i("JabberService login");
					Intent intent = new Intent(ACTION_CONNECTION_LOGIN);
					this.sendBroadcast(intent);
				}
			}
		} catch (Exception e) {
			Logger.e("Error when login to the server: " + e.getMessage(), e);
			Intent intent = new Intent(ACTION_CONNECTION_LOGIN_FAILED);
			this.sendBroadcast(intent);
		}
		return connection;
	}

	private ConnectionConfiguration getConnectionConfiguration() throws Exception {
		if (connectionConfiguration == null) {
			throw new Exception("Wrong call. connectionConfiguration is null");
		}
		return connectionConfiguration;
	}

	public JabberService() {
		super();
		XMPPConnection.addConnectionCreationListener(this);
		/*
		 * try{ if(ApplicationPreference.isAutoConnect(this)){
		 * this.getLoggInConnection(); } }catch(Exception e){ Logger.e(e); }
		 */
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub

		return binder;
	}

	public IJabberService.Stub getBinder() {
		return binder;
	}

	public void connectionCreated(XMPPConnection connection) {
		Logger.i("JabberService.connectionCreated() connected");
		JabberConnectionListener connectionListener = new JabberConnectionListener(this);
		connection.addConnectionListener(connectionListener);

		JabberPacketListener jpl = new JabberPacketListener(this);
		connection.addPacketListener(jpl, jpl);
		// PacketListener
		// PacketFilter
	}

	public void processMessage(Chat chat, Message message) {
		Logger.i("JabberService.processMessage()");
		if (message.getBody() != null) {
			message.setProperty("isExecuted", true);
			Intent intent = new Intent(ACTION_NEW_MESSAGE);
			intent.putExtra(ACTION_NEW_MESSAGE_CHAT, chat.getParticipant());
			intent.putExtra(ACTION_NEW_MESSAGE_BODY, message.getBody());
			this.sendBroadcast(intent);
		//	ChatProvider cp = new ChatProvider(account.getConnectionString(), this.getApplicationContext());
		//	cp.addEntry(new ChatEntry(message.getBody(), chat.getParticipant(), account.getConnectionString()));
			message.setProperty(NEW_MESSAGE_process, "processMessage");			
		}
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {

		super.onStartCommand(intent, flags, startId);
		Logger.i("JabberService.onStartCommand()");

		try {
			this.currentStatus = Status.OfLine;
			// if (ApplicationPreference.isAutoConnect(this)) {
			// this.binder.changeStatus(Status.OnLine.name());

			// }
		} catch (Exception e) {
			Logger.e(e);

		}
		// return START_STICKY;
		return START_NOT_STICKY;
	}

	@Override
	public void onDestroy() {
		Logger.i("JabberService.onDestroy()");
	}

	/*
	 * public IBinder connect(String connString){ try{ AccountProvider ap = new
	 * AccountProvider(this.getApplicationContext()); account =
	 * ap.getCurrentAccount(); connectionConfiguration = new
	 * ConnectionConfiguration(account.getJabberServer().getHost(),
	 * account.getJabberServer().getPort()); connection = new
	 * XMPPConnection(connectionConfiguration);
	 * 
	 * connection.login(account.getLogin(), account.getPassword()); }catch
	 * (Exception e) { Log.e("s", e.getMessage(), e); } return null; }
	 */

}
